﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DynaPrecision
{
	using LinearSystem;
	public static class ExtensionMethodIMultiDimensionalArray
	{
		public static IEnumerable<T> AsEnumerable<T>(this IMultiDimensionalArray<T> from)
		{
			int[] index = new int[from.Dimension];
			int lastCount = from.Dimension - 1;
			while (true)
			{
				yield return from[index];
				index[lastCount]++;
				for (int i = lastCount + 1; i > 1; i--)
				{
					if (index[i - 1] == from.GetLength(i - 1))
					{
						index[i - 1] = 0;
						index[i - 2] += 1;
					}
					else
					{
						break;
					}
				}
				if (index[0] == from.GetLength(0))
				{
					break;
				}
			}
		}
		public static IEnumerable<Pair<int[], T>> AsEnumerableWithIndex<T>(this IMultiDimensionalArray<T> from)
		{
			int[] index = new int[from.Dimension];
			int lastCount = from.Dimension - 1;
			while (true)
			{
				yield return new Pair<int[], T> { LeftValue = index.ToArray(), RightValue = from[index] };
				index[lastCount]++;
				for (int i = lastCount + 1; i > 1; i--)
				{
					if (index[i - 1] == from.GetLength(i - 1))
					{
						index[i - 1] = 0;
						index[i - 2] += 1;
					}
					else
					{
						break;
					}
				}
				if (index[0] == from.GetLength(0))
				{
					break;
				}
			}
		}
		public static IMultiDimensionalArray<T> TransposeArray<T>(this IMultiDimensionalArray<T> from)
		{
			if (from.Dimension != 2) throw new Exception("Transpose requires 2 dimension array");
			FunctionMappedArray<T> result = new FunctionMappedArray<T>();
			result.DimensionGetter = () => 2;
			result.LengthGetter = (_i) => from.GetLength(1 - _i);

			result.Setter = (v, i) => { from[i[1], i[0]] = v; };
			result.Getter = i => from[i[1], i[0]];

			return result;
		}
		public static int TotalLength<T>(this IMultiDimensionalArray<T> from)
		{
			int result = 1;
			for (int i = 0; i < from.Dimension; i++)
			{
				result *= from.GetLength(i);
			}
			return result;
		}
		public static IEnumerable<int> Lengths<T>(this IMultiDimensionalArray<T> from)
		{
			for (int i = 0; i < from.Dimension; i++)
			{
				yield return from.GetLength(i);
			}
		}
		public static MultiDimensionalArray<T> ToMultiDimensionalArray<T>(this IMultiDimensionalArray<T> from)
		{
			MultiDimensionalArray<T> result = new MultiDimensionalArray<T>(from.Lengths().ToArray());
			from.CopyToArray(result);
			return result;
		}
		public static void CopyToArray<T>(this IMultiDimensionalArray<T> from, IMultiDimensionalArray<T> To)
		{
			int[] index = new int[from.Dimension];
			int lastCount = from.Dimension - 1;
			while (true)
			{
				To[index] = from[index];
				index[lastCount]++;
				for (int i = lastCount + 1; i > 1; i--)
				{
					if (index[i - 1] == from.GetLength(i - 1))
					{
						index[i - 1] = 0;
						index[i - 2] += 1;
					}
					else
					{
						break;
					}
				}
				if (index[0] == from.GetLength(0))
				{
					break;
				}
			}
		}
	}
}